package org.word.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.word.exception.NotPostJsonReqException;
import org.word.model.Request;
import org.word.model.definition.SwaggerModelDefinition;
import org.word.model.definition.SwaggerModelDefinitionRef;
import org.word.model.definition.SwaggerModelProperty;
import org.word.model.path.ParameterItem;
import org.word.model.path.PathVOForPost;
import org.word.service.ModelDefinitionService;
import org.word.service.RequestParamService;
import org.word.utils.ModelDefinitionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static org.word.utils.ModelDefinitionUtils.fillChildPropertiesOfCurrentProperty;
import static org.word.utils.ModelDefinitionUtils.getSwaggerModelPropertyMap;

@Slf4j
@Service
public class RequestParamServiceImpl implements RequestParamService {
    @Autowired
    private ModelDefinitionService modelDefinitionService;


    @Override
    public List<Request> getRequestsParameterList( PathVOForPost pathVOForPost) {
        LinkedHashMap<String, SwaggerModelDefinition> definitionMap = modelDefinitionService.getDefinitionMap();
        List<ParameterItem> parameters = pathVOForPost.getParameters();


        ArrayList<ParameterItem> resultList = new ArrayList<>();
        /**
         * 遍历每个请求的请求参数集合
         */
        for (ParameterItem currentParameter : parameters) {

            List<ParameterItem> childParameterListOfCurrentParameter = getChildRequestParamListForCurrentParameter(definitionMap, currentParameter);
            if (CollectionUtils.isEmpty(childParameterListOfCurrentParameter)) {
                resultList.add(currentParameter);
                continue;
            } else {
                resultList.addAll(childParameterListOfCurrentParameter);
            }
        }

        /**
         * 转为界面展示时需要的数据结构：{@link Request}
         * 在界面展示时，按照level，分层级展示
         */
        List<Request> list = resultList.stream().map(parameterItem -> {
            Request request = new Request();

            StringBuilder builder = new StringBuilder();
            for (int i = 1; i < parameterItem.getLevel(); i++) {
                builder.append("-- ");
            }
            request.setName(builder.toString() + parameterItem.getName());
            request.setParamType(parameterItem.getType());
            request.setType(parameterItem.getIn());
            request.setRequire(parameterItem.getRequired());
            request.setRemark(parameterItem.getDescription());

            return request;
        }).collect(Collectors.toList());

        /**
         * 为空，展示一个空行
         */
        if (CollectionUtils.isEmpty(list)) {
            return Collections.singletonList(new Request());
        }

        return list;
    }


    /**
     * 如果返回不为空，说明有子property
     *
     *
     * @param swaggerModelDefinitions
     * @param parameterItem
     * @return
     */
    private List<ParameterItem> getChildRequestParamListForCurrentParameter( LinkedHashMap<String, SwaggerModelDefinition> swaggerModelDefinitions, ParameterItem parameterItem) {
        String in = parameterItem.getIn();
        /**
         * 不是post+json，抛错，暂不处理
         * todo:以后再加
         */
        if (!"body".equals(in)) {
            throw new NotPostJsonReqException();
        }

        SwaggerModelDefinitionRef schema = parameterItem.getSchema();
        if (schema != null) {
            String ref = schema.getRef();
            if (ref == null) {
                if (schema.getType() != null) {
                    parameterItem.setType(parameterItem.getType() + " -- " + schema.getType());
                    return new ArrayList<>();
                }
            }

            /**
             * 如果取出来的是一个，其他model的引用
             */
            LinkedHashMap<String, SwaggerModelProperty> properties = getSwaggerModelPropertyMap(swaggerModelDefinitions, ref);
            if (CollectionUtils.isEmpty(properties)) {
                return null;
            }

            /**
             * 遍历对象的property
             */
            ArrayList<ParameterItem> finalParameterItemList = new ArrayList<>();
            for (SwaggerModelProperty swaggerModelProperty : properties.values()) {
                /**
                 * 先把当前属性加入到结果
                 */
                ParameterItem currentParameterItem;
                {
                    currentParameterItem = new ParameterItem();
                    currentParameterItem.setLevel(swaggerModelProperty.getLevel());
                    currentParameterItem.setName(swaggerModelProperty.getKey());
                    currentParameterItem.setIn(parameterItem.getIn());
                    currentParameterItem.setType(swaggerModelProperty.getType());
                    currentParameterItem.setDescription(swaggerModelProperty.getDescription());
                    currentParameterItem.setRequired(parameterItem.getRequired());
                    currentParameterItem.setSchema(null);

                    finalParameterItemList.add(currentParameterItem);
                }

                /**
                 * 假设此时的properties如下，
                 * 那么，在访问disposalUserSet的时候，又要访问内部的bean
                 *
                 * "properties": {
                 *         "onOffStatus": {
                 *           "type": "integer",
                 *           "format": "int32",
                 *           "description": "开关状态，0：关闭；1：打开"
                 *         },
                 *         "disposalUserSet": {
                 *           "type": "array",
                 *           "description": "处警人员的集合",
                 *           "items": {
                 *             "$ref": "#/definitions/CadCommonUserVO"
                 *           }
                 *         }
                 *       },
                 *
                 */
                swaggerModelProperty.setLevel(parameterItem.getLevel());

                HashSet<String> visitedDefinitionType = new HashSet<>();
                List<SwaggerModelProperty> childModelPropertiesList = ModelDefinitionUtils.getChildPropertiesOfProperty(visitedDefinitionType, swaggerModelProperty,swaggerModelDefinitions);
                if (CollectionUtils.isEmpty(childModelPropertiesList)) {
                    continue;
                } else {
                    /**
                     * 有可能当前这个属性，是这种类型的：
                     *     @ApiModelProperty(value = "障碍几何", notes = "表示障碍物的几何形状（wkt），与障碍图形相交的道路不允许通过")
                     *     private String[] barriers;
                     * 此时，json中就是如下格式：
                     * "properties": {
                     *         "barriers": {
                     *           "type": "array",
                     *           "description": "障碍几何",
                     *           "items": {
                     *             "type": "string"
                     *           }
                     *         },
                     *  这种如果不加下面的处理，就会显示成下面这样：
                     *  参数名	数据类型	是否必填	说明
                     * barriers	array	Y	障碍几何
                     * -- null	string	Y
                     *  这种简单类型，我们希望，直接显示为array<string>
                     *  所以，要判断如果只有一个元素，就要去掉最后加的这一个，同时，修改当前的array元素
                     */
                    if (childModelPropertiesList.size() == 1) {
                        /**
                         * 修改原array属性的type为array<xxx>
                         */
                        String arrayItemType = childModelPropertiesList.get(0).getType();
                        String type = currentParameterItem.getType() + "<" + arrayItemType + ">";
                        currentParameterItem.setType(type);
                        /**
                         * 将sub属性的集合，清空
                         */
                        childModelPropertiesList.clear();
                        continue;
                    }
                }
                /**
                 * 修改
                 */
                fillChildPropertiesOfCurrentProperty(parameterItem, finalParameterItemList, childModelPropertiesList);
            }

            return finalParameterItemList;
        }

        return null;
    }



}
